package com.linjinp.study.并发编程.forkjoin;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 *  fork/join有返回值示例，打印每个分片的累加值，并且打印最终累加结果
 * @Author: linjinp
 * @Date: 2021/6/2 10:46
 */
public class SumArrayTask extends RecursiveTask<Integer> {

    // 数组
    private int[] src;
    // 初始索引位
    private int fromIndex;
    // 结束索引位
    private int toIndex;
    // 每份个数，分片大小。大概分为 10 份左右，可有所偏移
    private int shard = MakeArray.ARRAY_LENGTH / 16;

    public SumArrayTask(int[] src, int fromIndex, int toIndex) {
        this.src = src;
        this.fromIndex = fromIndex;
        this.toIndex = toIndex;
    }

    @Override
    protected Integer compute() {
        // 如果小任务符合要求
        // 这里通过前后索引相减，小于等于每片的数量，就算符合要求
        if (toIndex - fromIndex <= shard) {
            // 累加数据
            int count = 0;
            for (int i = fromIndex; i <= toIndex; i ++) {
                count = count + src[i];
            }
            System.out.println("此分片累加结果" + count);
            return count;
        } else {
            // 走到下面，说明不满足分片要求，对数据继续进行拆分
            int mid = (fromIndex + toIndex) / 2;
            // 拆分出两个更小的任务
            // 通过计算出，索引位的中间位，将任务拆为前后两个任务
            SumArrayTask left = new SumArrayTask(src, fromIndex, mid);
            SumArrayTask right = new SumArrayTask(src, mid + 1, toIndex);
            // 将任务加入 fork/join 池子
            // 这里因为池子已经存在，因此可以直接 invokeAll 加入
            invokeAll(left, right);
            // 通过 join 函数拿到两个任务的返回值，进行累加
            return left.join() + right.join();
        }
    }

    public static void main(String[] args) {
        // 创建 fork/join 任务池子
        ForkJoinPool pool = new ForkJoinPool();
        // 创建初始任务
        SumArrayTask sumArrayTask = new SumArrayTask(MakeArray.makeArray(), 0 , MakeArray.ARRAY_LENGTH - 1);
        // 将任务加入池子
        pool.invoke(sumArrayTask);
        // 利用 join 函数拿到最终累加结果并且打印
        System.out.println(sumArrayTask.join());
    }
}
